/*
 * JANN - a Java toolkit for creating arbitrary Artificial Neural Networks.
 * 
 * Copyright (c) 2009 Matthijs Snel
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.jann.ui;
import net.jann.Link;
import net.jann.Neuron;

import org.jhotdraw.draw.AttributeKeys;
import org.jhotdraw.draw.BezierLabelLocator;
import org.jhotdraw.draw.Connector;
import org.jhotdraw.draw.Figure;
import org.jhotdraw.draw.FigureAdapter;
import org.jhotdraw.draw.FigureEvent;
import org.jhotdraw.draw.FigureListener;
import org.jhotdraw.draw.LabeledLineConnectionFigure;
import org.jhotdraw.draw.LocatorLayouter;
import org.jhotdraw.draw.TextFigure;
import org.jhotdraw.samples.pert.figures.TaskFigure;


import java.awt.Color;
import java.text.NumberFormat;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;

public class LinkFigure extends LabeledLineConnectionFigure implements Observer {

	protected Link model;
	protected TextFigure text;
	protected NumberFormat format;
	
	private boolean highlighted = false,
					weightDisplayed = false;
	private static final long serialVersionUID = 7664657570706539013L;
	
	public LinkFigure() {
		super();
		initNumberFormat();
		createTextLabel();
	}
	
	public LinkFigure( Link model ) {
		this();
		setModel( model );
	}
	
	public Link getModel() {
		return model;
	}
	
	@Override 
	public boolean canConnect(Connector start, Connector end) {
		if ((start.getOwner() instanceof NeuronFigure)
		&& (end.getOwner() instanceof NeuronFigure)) {
			
			return !existingConnection( (NeuronFigure) start.getOwner(), (NeuronFigure) end.getOwner());
		}
		return false;
	}
	
	@Override
	public boolean canConnect(Connector start) {
        return (start.getOwner() instanceof NeuronFigure);
    }
	
	public void displayWeight( boolean display ) {
		if ( weightDisplayed == display )
			return;
		weightDisplayed = display;
		if ( display ) {
			text.setVisible(true); 
			text.setText( format.format( model.getWeight() ));
		}
		else
			text.setVisible(false); 
	}
	
	public boolean isHighlighted() {
		return highlighted;
	}

	public void setHighlighted(boolean highlighted) {
		if ( this.highlighted == highlighted )
			return;
		this.highlighted = highlighted;
		if ( highlighted ) {
			AttributeKeys.STROKE_COLOR.set(this, Color.red);
			displayWeight(true);
		} else {
			AttributeKeys.STROKE_COLOR.set(this, Color.black);
			displayWeight(false);
		}
	}
	
	public void setModel( Link model ) {
		this.model = model;
		model.addObserver(this);
	}
	
	public void update( Observable obs, Object o ) {
		if ( weightDisplayed )
			text.setText( format.format( model.getWeight() ));
	}
	
	protected void createTextLabel() {
		text = new TextFigure();
        LocatorLayouter.LAYOUT_LOCATOR.basicSet(text, new BezierLabelLocator(0.5, 1, 1));
        text.setText("");
        text.setEditable(true);
        text.addFigureListener(new EventHandler());
        this.add(text);
	}
	
	protected void handleConnect( Connector start, Connector end ) {
		super.handleConnect( start, end );
		
		NeuronFigure 	preFig = (NeuronFigure) start.getOwner(),
						postFig = (NeuronFigure) end.getOwner();
		
		preFig.addOutputLink(this);
		postFig.addInputLink(this);
		
		Neuron	pre = preFig.getModel(),
				post = postFig.getModel();
		
		Link currLink = findLink(pre, post);
		if ( model == null ) {
			setModel( (currLink == null ? new Link(pre, post) : currLink) );
		}
		else if ( currLink == null ){
			model.setPreNeuron(pre);
			model.setPostNeuron(post);
		} else { //Should never get here!
			throw new RuntimeException("Only 1 link allowed between 2 neurons");
		}
	}
	
	protected boolean existingConnection( NeuronFigure from, NeuronFigure to ) {
		for ( LinkFigure f : from.getOutgoing() )
			if ( f.getEndFigure() == to )
				return true;
		return false;
	}
	
	protected Link findLink(Neuron pre, Neuron post) {
		for ( Link l : pre.getOutgoing() )
			if ( l.getPostNeuron() == post )
				return l;
		return null;
	}
	
	protected void initNumberFormat() {
		format = NumberFormat.getInstance();
		format.setMaximumFractionDigits(2);
		format.setMinimumFractionDigits(2);
	}
	
	protected class EventHandler extends FigureAdapter {
		public void attributeChanged(FigureEvent e) {
			if ( e.getAttribute() == AttributeKeys.TEXT )
				model.setWeight( Double.parseDouble(text.getText()) );
		}
	}
}
